package com.wangyf.thread.c_009_sync_atomic_loadr_test;

import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;

/**
 * 对比 synchronized AtomicLong LongAdder 耗时
 * @author wangyf
 * @date 2021/1/2 22:23
 *
 * 通过修改threadNum、addCount：
 * 情景1：
 *      线程数量[1]，++次数[10000000]：
 *          sync            276
 *          AtomicLong      85
 *          LongAdder       131
 *      结论：单线程情景下 atomicLong 效率最高
 * 情景2：
 *      线程数量[2]，++次数[10000000]：
 *          sync            851
 *          AtomicLong      363
 *          longAdder       127
 *      结论：两个线程情景下 LongAdder 效率最高
 * 情景3：
 *      线程数量[1000]，++次数[100000]：
 *          sync            5383
 *          AtomicLong      1972
 *          longAdder       497
 *      结论：多线程情景下 LongAdder 效率最高
 * 解释：多线程情况下 atomicLong 效率高于 sync，原因是 sync需要加锁，可能是重量级锁
 *       longAdder 效率高于 atomicLong，原因是LongAdder内部是做了类似分段锁的概念，比如1000个线程 分别变成4个
 */
public class T {
    static Long count1 = 0l;
    static AtomicLong count2 = new AtomicLong(0l);
    static LongAdder count3 = new LongAdder();
    static int threadNum = 1000;// 线程数量
    static int addCount = 100000;// 每个线程 ++ 次数
    static Thread[] threads = new Thread[threadNum];

    public static void main(String[] args) throws InterruptedException {
        test01(); // 5324
        test02(); // 1839
        test03(); // 467
    }

    private static void test01() throws InterruptedException {
        final Object lock = new Object();
        for (int i = 0; i < threads.length; i++) {
            threads[i] = new Thread(() -> {
                for (int j = 0; j < addCount; j++) {
                    synchronized (lock) {
                        count1++;
                    }
                }
            });
        }
        long l = System.currentTimeMillis();
        for (Thread thread : threads) {
            thread.start();
        }
        for (Thread thread : threads) {
            thread.join();
        }
        long l1 = System.currentTimeMillis();
        System.out.println("count1: "+count1);
        System.out.println("sync耗时: "+(l1-l));
    }
    private static void test02() throws InterruptedException {
        for (int i = 0; i < threads.length; i++) {
            threads[i] = new Thread(() -> {
                for (int j = 0; j < addCount; j++)
                    count2.incrementAndGet();
            });
        }
        long l = System.currentTimeMillis();
        for (Thread thread : threads) {
            thread.start();
        }
        for (Thread thread : threads) {
            thread.join();
        }
        long l1 = System.currentTimeMillis();
        System.out.println("count2: "+count2.get());
        System.out.println("atomicLong耗时: "+(l1-l));
    }
    private static void test03() throws InterruptedException {
        for (int i = 0; i < threads.length; i++) {
            threads[i] = new Thread(() -> {
                for (int j = 0; j < addCount; j++)
                    count3.increment();
            });
        }
        long l = System.currentTimeMillis();
        for (Thread thread : threads) {
            thread.start();
        }
        for (Thread thread : threads) {
            thread.join();
        }
        long l1 = System.currentTimeMillis();
        System.out.println("count3: "+count3.longValue());
        System.out.println("longAdder耗时: "+(l1-l));
    }
}
